#ifndef CMATRIXBASE_H_
#define CMATRIXBASE_H_

#include <vector>
#include "cvector.h"
#include "../exception/cmatrixnotsquareexception.h"

/**
 * CMatrixBase - abstract parent of all matrices
 * @author Michal Rost
 * @date 12.10.2007
 */
template <typename T> class CMatrixBase : public CObject {
public:
  CMatrixBase<T>& operator +=(const CMatrixBase<T> &m);
  CMatrixBase<T>& operator -=(const CMatrixBase<T> &m);
  CMatrixBase<T>& operator *=(const CMatrixBase<T> &m);
  CMatrixBase<T>& operator *=(T num);
  CMatrixBase<T>& operator /=(T num);
  bool operator ==(const CMatrixBase<T> &m) const;
  bool operator !=(const CMatrixBase<T> &m) const;
  CVector<T> getRow(TIndex index) const;
  CVector<T> getCol(TIndex index) const;
  T get(TIndex row, TIndex col) const;
  void set(TIndex row, TIndex col, T value);
  void swapRows(TIndex index1, TIndex index2);
  void multiplyRow(TIndex index, T num);
  void divideRow(TIndex index, T num);
  T elimCol(TIndex row, TIndex col);
  T elimColUnder(TIndex row, TIndex col);
  void doLUDecomposition(CMatrixBase<T> &l, CMatrixBase<T> &u) const;
  void clearToIdentity();
  void clearToZero();
  void transpose();
  TIndex doGaussElimination();
  bool doGaussJordanElimination();
  bool toLowerTriangular();
  bool isSymmetric() const;
  bool isSquare() const;
  bool isUpperTriangular() const;
  string toString() const;
  virtual TIndex getNumOfRows() const = 0;
  virtual TIndex getNumOfCols() const = 0;
  T** getItemsPtr() const;
  static CVector<T> mul(const CMatrixBase<T> &m, const CVector<T> &v);
  static CVector<T> mul(const CVector<T> &v, const CMatrixBase<T> &m);
  static string getClassName() {
    return "CMatrixBase";
  }
  static const int VECTOR_ROW = 0;
  static const int VECTOR_COL = 1;
  static const TIndex M3X3_SIZE = 3;
  static const TIndex M4X4_SIZE = 4;
  static const TIndex M3X3_NUM_OF_ITEMS = 9;
  static const TIndex M4X4_NUM_OF_ITEMS = 16;
protected:
  T** items;
  static T** createItems(TIndex numOfRows, TIndex numOfCols);
  void copyFrom(const CMatrixBase<T> &m);
  bool doPivoting(TIndex row, TIndex col);
  void init(TIndex numOfRows, TIndex numOfCols);
  void init(TIndex numOfRows, TIndex numOfCols, T items[]);
  void init(int type, vector<CVector<T> > v);
  void init(int type, TIndex numOfVectors, CVector<T> v[]);
  void init(const CMatrixBase<T> &m, const CVector<T> &v, int vType);
  void init(const CMatrixBase<T> &m1, const CMatrixBase<T> &m2);
  void reset(TIndex numOfRows, TIndex numOfCols, T** items);
  void free();
  virtual void setNumOfRows(TIndex numOfRows) = 0;
  virtual void setNumOfCols(TIndex numOfCols) = 0;
};

#endif
